package com.xiqi.microservice.auth.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiqi.microservice.auth.config.JWTAuthenticationConfig;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Date;
import java.time.Instant;
import java.util.Collections;
import java.util.stream.Collectors;

/**
 * @program: authcommons
 * @description:
 * @author: Shine
 * @create: 2019-08-01 13:29
 */
public class JWTUserNameAndPasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private JWTAuthenticationConfig jwtAuthenticationConfig;

    private ObjectMapper objectMapper;

    protected JWTUserNameAndPasswordAuthenticationFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }

    public JWTUserNameAndPasswordAuthenticationFilter(RequestMatcher matcher){
        super(matcher);
    }

    public JWTUserNameAndPasswordAuthenticationFilter(JWTAuthenticationConfig config, AuthenticationManager authenticationManager){
        super(new AntPathRequestMatcher(config.getUrl(),"POST"));
        setAuthenticationManager(authenticationManager);
        objectMapper = new ObjectMapper();
        this.jwtAuthenticationConfig = config;

    }

    /**
     * @Author: Shine
     * @Date: 19-8-1 下午1:37
     * @Description: 验证开始：用户名和密码
     * @Param: HttpServletRequest HttpServletResponse
     * @return:
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        //必须用post
        ServletInputStream inputStream = request.getInputStream();
        User user = objectMapper.readValue(inputStream, User.class);
        return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword(), Collections.emptyList()));
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response, FilterChain chain, Authentication authResult){
        Instant now = Instant.now();
        //计算生成token
        String token = Jwts.builder().setSubject(authResult.getName()).claim("authorities", authResult.getAuthorities().
                stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())).setIssuedAt(Date.from(now)).
                setExpiration(Date.from(now.plusSeconds(jwtAuthenticationConfig.getExpriation()))).
                signWith(SignatureAlgorithm.HS256, jwtAuthenticationConfig.getSecret().getBytes()).compact();
        //反给客户
        response.addHeader(jwtAuthenticationConfig.getHeader(),jwtAuthenticationConfig.getPrefix()+""+token);
    }

    private static class User{
        private String username,password;

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}
